<?php

namespace magein\utils;

class DateFormatter
{

    /**
     * 现在的时间
     * @return false|string
     */
    public static function now()
    {
        return date('Y-m-d H:i:s');
    }

    /**
     * 转化为时间戳
     * @param $datetime
     * @return bool|false|int
     */
    public static function unixtime($datetime)
    {
        if (empty($datetime)) {
            return '';
        }

        if (preg_match('/^[0-9]+$/', $datetime)) {
            return substr($datetime, 0, 10);
        }

        $result = strtotime($datetime);
        if (false === $result) {
            return '';
        }

        if ($result < 0) {
            return '';
        }

        return $result;
    }

    /**
     * 格式化时间
     * @param string $datetime
     * @return string
     */
    public static function datetime(string $datetime = ''): string
    {
        if (empty($datetime)) {
            $datetime = time();
        }

        $datetime = self::unixtime($datetime);

        return date('Y-m-d H:i:s', $datetime);
    }

    /**
     * @param string $datetime
     * @return string
     */
    public static function date(string $datetime = ''): string
    {
        if (empty($datetime)) {
            $datetime = time();
        }

        return date('Y-m-d', self::unixtime($datetime));
    }

    /**
     * 获取时间
     * @param string $datetime
     * @return string
     */
    public static function time(string $datetime = ''): string
    {
        if (empty($datetime)) {
            $datetime = time();
        }

        return date('H:i:s', self::unixtime($datetime));
    }

    /**
     * 某天的开始时间点
     * @param string $date
     * @param bool $unixtime
     * @return string
     */
    public static function begin(string $date = '', bool $unixtime = false): string
    {
        $begin = self::date($date) . ' 00:00:00';

        return $unixtime ? self::unixtime($begin) : $begin;
    }

    /**
     * 某天结束时间点
     * @param string $date
     * @param bool $unixtime
     * @return string
     */
    public static function end(string $date = '', bool $unixtime = false): string
    {
        $end = self::date($date) . ' 23:59:59';

        return $unixtime ? self::unixtime($end) : $end;
    }

    /**
     * 今天
     * @param bool $unixtime
     * @return array
     */
    public static function today(bool $unixtime = false): array
    {
        return [self::begin('', $unixtime), self::end('', $unixtime)];
    }

    /**
     * 昨天
     * @param bool $unixtime
     * @return array
     */
    public static function yesterday(bool $unixtime = false): array
    {
        $start = $end = date('Y-m-d', strtotime('-1 day'));

        return [self::begin($start, $unixtime), self::end($end, $unixtime)];
    }

    /**
     * 明天
     * @param bool $unixtime
     * @return array
     */
    public static function tomorrow(bool $unixtime = false): array
    {
        $start = $end = date('Y-m-d', strtotime('+1 day'));

        return [self::begin($start, $unixtime), self::end($end, $unixtime)];
    }

    /**
     * 指定天的开始和结束时间
     * @param string $date
     * @param bool $unixtime
     * @return array
     */
    public static function dayRange(string $date, bool $unixtime = false): array
    {
        return [self::begin($date, $unixtime), self::end($date, $unixtime)];
    }

    /**
     * 获取本周的日期范围
     * @param bool $unixtime
     * @return array
     */
    public static function week(bool $unixtime = false): array
    {
        $start = date('Y-m-d', strtotime('monday this week'));
        $end = date('Y-m-d', strtotime('sunday this week'));

        return [self::begin($start, $unixtime), self::end($end, $unixtime)];
    }

    /**
     * 最后一周
     * @param bool $unixtime
     * @return array
     */
    public static function lastWeek(bool $unixtime = false): array
    {
        $start = date('Y-m-d', strtotime('monday last week'));
        $end = date('Y-m-d', strtotime('sunday last week'));

        return [self::begin($start, $unixtime), self::end($end, $unixtime)];
    }

    /**
     * 获取指定月份的开始到结束时间
     * @param string|null $month 可以使年-月-日的格式
     * @param bool $unixtime
     * @return array
     */
    public static function month(string $month = null, bool $unixtime = false): array
    {
        if (empty($month)) {
            $month = 'this month';
        } elseif (is_numeric($month)) {
            $month = intval($month);
            if ($month <= 0 || $month > 12) {
                $month = 1;
            }
            $trans = [
                1 => 'January',
                2 => 'February',
                3 => 'March',
                4 => 'April',
                5 => 'May',
                6 => 'June',
                7 => 'July',
                8 => 'August',
                9 => 'September',
                10 => 'October',
                11 => 'November',
                12 => 'December'
            ];
            $month = $trans[$month] . ' ' . date('Y');
        }

        $start = date('Y-m-d', strtotime('first day of ' . $month));
        $end = date('Y-m-d', strtotime('last day of ' . $month));

        return [self::begin($start, $unixtime), self::end($end, $unixtime)];
    }

    /**
     * 获取上个月的日期范围
     * @param bool $unixtime
     * @return array
     */
    public static function lastMonth(bool $unixtime = false): array
    {
        $start = date('Y-m-d', strtotime('first day of last month'));
        $end = date('Y-m-d', strtotime('last day of last month'));

        return [self::begin($start, $unixtime), self::end($end, $unixtime)];
    }

    /**
     * 获取前x天的日期范围
     * @param int $days
     * @param bool $unixtime
     * @return array
     */
    public static function prevDay(int $days = 7, bool $unixtime = false): array
    {
        $start = date('Y-m-d', strtotime("-$days days"));
        $end = date('Y-m-d', strtotime("-1 days"));

        return [self::begin($start, $unixtime), self::end($end, $unixtime)];
    }

    /**
     * 获取前30天的日期范围
     * @param string $date_format
     * @return array
     */
    public static function prev30Days(string $date_format = 'datetime'): array
    {
        return self::prevDay(30, $date_format);
    }

    /**
     * 获取近x天的日期范围 包含今天
     * @param int $days
     * @param bool $unixtime
     * @return array
     */
    public static function lastDay(int $days = 7, bool $unixtime = false): array
    {
        if ($days <= 0) {
            $days = 1;
        }

        $days = $days - 1;

        $start = date('Y-m-d', strtotime("-$days days"));
        $end = date('Y-m-d');

        return [self::begin($start, $unixtime), self::end($end, $unixtime)];
    }

    /**
     * 获取近30天的日期范围  包含今天
     * @param bool $unixtime
     * @return array
     */
    public static function last30Days(bool $unixtime = false): array
    {
        return self::lastDay(30, $unixtime);
    }

    /**
     * 格式化时间
     * @param $date
     * @param string $lang
     * @return string
     */
    public static function humans($date, string $lang = 'zh'): string
    {
        $timestamp = self::unixtime($date);

        $diff = time() - $timestamp;

        // 定义时间单位和对应的秒数
        $units = [
            'year' => 31536000,
            'month' => 2592000,
            'week' => 604800,
            'day' => 86400,
            'hour' => 3600,
            'minute' => 60,
            'second' => 1,
        ];

        $map = [
            'zh' => [
                'just_now' => '刚刚',
                'ago' => '前',
                'later' => '后',
                'units' => [
                    'year' => '年',
                    'month' => '个月',
                    'week' => '周',
                    'day' => '天',
                    'hour' => '小时',
                    'minute' => '分钟',
                    'second' => '秒',
                ],
            ],
            'en' => [
                'just_now' => 'just now',
                'ago' => 'ago',
                'later' => 'later',
                'units' => [
                    'year' => ' year',
                    'month' => ' month',
                    'week' => ' week',
                    'day' => ' day',
                    'hour' => ' hour',
                    'minute' => ' minute',
                    'second' => ' second',
                ],
            ],
        ];

        if ($diff < 0) {
            $diff = abs($diff);
            $suffix = $map[$lang]['later'];
        } else {
            $suffix = $map[$lang]['ago'];
        }

        if ($diff <= 10) {
            return $map[$lang]['just_now'];
        }

        foreach ($units as $unit => $seconds) {
            if ($diff >= $seconds) {
                $count = floor($diff / $seconds);
                $unitText = $map[$lang]['units'][$unit];

                if ($lang === 'en' && $count > 1) {
                    $unitText .= 's';
                }

                return "{$count}{$unitText}{$suffix}";
            }
        }

        return $map[$lang]['just_now'] ?? '';
    }
}